#将表情列表处理重复后生成矩阵
#并计算出所需的5个特征值
import csv
import numpy as np
import numpy.matlib

#根据论文中的计算方法，计算每一帧的表情预测值，生成新的矩阵
'''
            & W_p       & W_a       & W_d
        困倦  & -0.12     & -1.16     & -0.60 
        疑惑  & 1.0525    & 1.3625    & -0.41
        中性  & 0         &       0   & 0 
        愉悦  & 2.77      & 1.21      & 1.42 
'''

'''
对于当前的表情概率，可以构建学生在不同维度下课堂状态值E_p、E_a、E_d 
用w_p、w_a、w_d 分别代表PAD模型中对应三个维度的权重
k是四种不同表情的标号，取值范围为[1,2,3,4]
P_k是当前表情的预测率值，avg是以某时刻的表情在三个维度状态值和的平均值作为对学生当前表情的特征值。
0.0054,0.0002,0.3451,0.6493
'''
W_p = np.array([[-0.12],[1.0525],[0.0],[2.77]])
W_a = np.array([[-1.16],[1.3625],[0.0],[1.21]])
W_d = np.array([[-0.60],[1.2100],[0.0],[1.42]])

#将第一次生成的每一帧表情预测值读入并去重然后生成unique矩阵存储
def unique_exps_arry(detected_probability_file):
    my_file = open(detected_probability_file)  # 打开csv文件
    my_reader = csv.reader(my_file)  # 读取csv文件
    my_data = list(my_reader)  # csv数据转换为列表

    lst_row = len(my_data)  # 得到数据行数
    lst_col = len(my_data[0])  # 得到每行长度

    with open(detected_probability_file + "_list.csv", 'w',newline='') as f:
        csv_writer = csv.writer(f)
        csv_writer.writerow(my_data[0])
        for i in range(0, lst_row):  # 从第1行开始读取
            if float(my_data[i][0]) >= 2:
                csv_writer.writerow(my_data[i])

    ordinary_arry = np.loadtxt(open(detected_probability_file + "_list.csv","rb"),delimiter=",",usecols=[1,2,3,4])
    rows = ordinary_arry.shape[0]
    cols = ordinary_arry.shape[1]
    unique_arry = np.zeros((rows,cols))#生成指定cols行rows列数的全0.0矩阵
    unique_arry[0,:] = ordinary_arry[0,:]
    for i in range(0,rows):
        unique_arry[i,:] = ordinary_arry[i,:]
    np.savetxt(detected_probability_file+'._unique.csv',unique_arry, fmt='%.4f', delimiter=",")
    return unique_arry

#获取每个时刻表情的PAD模型值矩阵，并存储下来
def get_avg(exps_matrix):
    #除了第一列，其余列都用，因为第一列是标号，row_number是矩阵的行数
    row_number = exps_matrix.shape[0]
    avg_arry = np.zeros((1,row_number))#生成指定1行row_number列数的全0.0矩阵，存储接下来的各个帧表情得分值
    #计算每一行的表情在PAD模型下得分，存储到新的矩阵中
    for i in range(0,row_number):
        E_p = np.dot (exps_matrix[i],W_p)
        E_a = np.dot (exps_matrix[i],W_a)
        E_d = np.dot (exps_matrix[i],W_d)
        avg = (E_p + E_a + E_d)/3.0
        #该操作将之前的每一个avg值存储到每个学生在一节课时间上的得分矩阵中
        avg_arry[0,i] = avg
    np.savetxt(str(my_csv_path)+'._avg_arry.csv',avg_arry, fmt='%.4f', delimiter=",")
    return avg_arry

#计算表情值矩阵行向量的均值，方差，标准差
def get_mean_var_std(arry):
    #求均值
    arry_mean = np.mean(arry)
    #求方差
    arry_var = np.var(arry)
    #求标准差
    arry_std = np.std(arry,ddof=1)
    #输出行向量的各项值
    print("************************************")
    print("行向量均值：%.6f" % arry_mean)
    print("行向量方差：%.6f" % arry_var)
    print("行向量标准差:%.6f" % arry_std)
    print("************************************")
    return arry_mean ,arry_var ,arry_std

#计算两个行向量之间的距离
def get_distance(vec_x,vec_y):
    distance = np.linalg.norm(vec_x - vec_y)
    #distance2 = np.sqrt(np.sum(np.square(vec_y - vec_x)))#这里有两种计算方法，结果是一样的
    print("按冒泡法任意两个行向量的距离：",distance)
    #print("第2个和第1个行向量的距离：",distance2)
    print("************************************")
    return distance

if __name__ == "__main__":
    my_csv_paths = ["detected_probability_masked_s1.csv","detected_probability_masked_s2.csv","detected_probability_masked_s3.csv","detected_probability_masked_s4.csv"]
    for my_csv_path in my_csv_paths:
        a = unique_exps_arry(my_csv_path)
        b = get_avg(a)
        c = get_mean_var_std(b)

    #这部分实现任意两个行向量不重复的比较大小
    #由于x和y的欧式距离与 y和x的欧式距离是一样的，而且同一个向量没有比较欧氏距离的必要（距离为0）
    #因此对于2个以上数量的向量，其比较次数必定为1+2+3+...+(n-1)也就是 n*(n1)/2或者用排列C-n-2
    i = 0
    while (i < len(my_csv_paths)):
        for j in range(i + 1,len(my_csv_paths)):
            print(my_csv_paths[i])
            print(my_csv_paths[j])
            vec_x = get_avg(unique_exps_arry(my_csv_paths[i]))
            vec_y = get_avg(unique_exps_arry(my_csv_paths[j]))
            get_distance(vec_x,vec_y)
        i = i + 1